package com.github.eprendre.sources_by_xx

import com.github.eprendre.tingshu.sources.AudioUrlCustomExtractor
import com.github.eprendre.tingshu.sources.AudioUrlExtractor
import com.github.eprendre.tingshu.sources.ILogin
import com.github.eprendre.tingshu.sources.TingShu
import com.github.eprendre.tingshu.utils.*
import com.github.kittinunf.fuel.Fuel
import com.github.kittinunf.fuel.json.responseJson
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.json.JSONArray

object XXBaidu : TingShu(), ILogin {
    //    val tokenUrl = "http://image.cbstest.release.360cbs.com/config.txt"
    val tokenUrl = "https://dist.360cbs.com/tingshu/config.json"

    private fun loadConfig() {
        try {
            val config = Fuel.get(tokenUrl).responseJson().third.get().obj();
            ExternalSourcePrefs.putString("xxbaidu_token", config.getString("token"))
            ExternalSourcePrefs.putString("xxbaidu_entrancepath", config.getString("entrancepath"))
        } catch (_: Exception) {
        }
    }

    private fun getToken(): String {
        return ExternalSourcePrefs.getString("xxbaidu_token", "") ?: ""
    }

    private fun getEntrancePath(): String {
        return ExternalSourcePrefs.getString("xxbaidu_entrancepath", "") ?: ""
    }

    fun getCoverStorage(): HashMap<String, HashMap<String, String>> {
        val serializedData = ExternalSourcePrefs.getString("xxbaidu_covercache", "") ?: ""

        val type = object : TypeToken<HashMap<String, HashMap<String, String>>>() {}.type
        val coverCache = try {
            Gson().fromJson<HashMap<String, HashMap<String, String>>>(serializedData, type)
                ?: HashMap()
        } catch (e: Exception) {
            HashMap() // 反序列化失败时返回空Map
        }

        return coverCache
    }

    fun setCoverStorage(storage: HashMap<String, HashMap<String, String>>) {
        ExternalSourcePrefs.putString("xxbaidu_covercache", Gson().toJson(storage))
    }

    fun getCoverCache(storage: HashMap<String, HashMap<String, String>>, key: String): String {
        for ((_, innerMap) in storage) {
            innerMap[key]?.let {
                return it
            }
        }
        return ""
    }

    fun setCoverCache(storage: HashMap<String, HashMap<String, String>>, key: String, cover: String) {
        storage.values.forEach { innerMap ->
            if (innerMap.containsKey(key)) {
                innerMap[key] = cover
                return@forEach // 仅修改第一个匹配项
            }
        }
    }

    override fun getSourceId(): String {
        return "b1ac30b4518a4ff1d2b1daf769caa25b"
    }

    override fun getUrl(): String {
        return "https://pan.baidu.com"
    }

    override fun getName(): String {
        return "XX百度网盘"
    }

    override fun getDesc(): String {
        return "百度网盘XX版"
    }

    override fun getLoginUrl(): String {
        return "https://dcsmart.dev.dashengiot.cn/ts/"
    }

    override fun search(keywords: String, page: Int): Pair<List<Book>, Int> {
        return Pair(emptyList(), 1)
    }

    override fun isSearchable(): Boolean {
        return false
    }

    override fun isCacheable(): Boolean {
        return true
    }

    override fun getAudioUrlExtractor(): AudioUrlExtractor {
        AudioUrlCustomExtractor.setUp { fsid ->
            return@setUp getDLinks(arrayOf(fsid))[fsid] ?: ""
        }
        return AudioUrlCustomExtractor
    }

    override fun getCategoryMenus(): List<CategoryMenu> {
        loadConfig()
        val data = getFiles(getEntrancePath(), false)
        val list = ArrayList<CategoryTab>()
        run loop@{
            (0 until data.length()).forEach {
                val result = data.getJSONObject(it)
                val isDir = result.getInt("isdir")

                if (isDir == 1) {
                    val serverFilename = result.getString("server_filename")
                    val path = result.getString("path")
                    list.add(CategoryTab(serverFilename, path))
                }
            }
        }
        return listOf(CategoryMenu("百度网盘", list))
    }

    override fun getCategoryList(url: String): Category {
        val data = getFiles(url, false)
        val list = ArrayList<Book>()
        val coverStorage = getCoverStorage()
        val subCoverStorage = HashMap<String, String>()
        val coverFsids = ArrayList<String>()
        run loop1@{
            (0 until data.length()).forEach { it ->
                val result = data.getJSONObject(it)
                val isDir = result.getInt("isdir")

                if (isDir == 1) {
                    val serverFilename = result.getString("server_filename")
                    val filenameParts = serverFilename.split("_") // 使用下划线作为分隔符
                    val author = filenameParts.getOrNull(1) ?: "未知"
                    val artist = filenameParts.getOrNull(2) ?: "未知"

                    val path = result.getString("path")
                    val coverFsid = getCoverCache(coverStorage, path)
                    subCoverStorage[path] = coverFsid
                    if (coverFsid.isNotEmpty()) coverFsids.add(coverFsid)
                    val bookUrl = path

                    val titleStr = filenameParts.getOrNull(0) ?: "未知"
                    val title: String
                    var status = ""
                    var intro = ""
                    if (!titleStr.contains("(") || !titleStr.contains(")")) {
                        title = titleStr
                    } else {
                        // 提取小说名（括号之前的部分）
                        title = titleStr.substringBefore("(").trim()

                        // 提取括号内的内容
                        val bracketContent = titleStr.substringAfter("(").substringBefore(")").trim()

                        // 判断括号内是否有集数（数字）
                        val episodeRegex = Regex("""\d+""")
                        val episodeMatch = episodeRegex.find(bracketContent)

                        if (episodeMatch != null) {
                            // 有集数，分别提取状态和集数
                            status = bracketContent.substringBefore(episodeMatch.value).trim()
                            intro = status + episodeMatch.value + "集"
                        } else {
                            status = bracketContent.ifEmpty { "" }
                        }
                    }

                    list.add(Book(coverFsid, bookUrl, title, author, artist).apply {
                        this.status = status
                        this.intro = intro
                        this.sourceId = getSourceId()
                    })
                }
            }
        }
        coverStorage[url] = subCoverStorage
        setCoverStorage(coverStorage)
        val coverUrls = getDLinks(coverFsids.toTypedArray())
        list.forEach { book ->
            book.coverUrl = coverUrls[book.coverUrl] ?: ""
        }
        list.sortedBy { it.title }
        return Category(list, 1, 1, "", "")
    }

    override fun getBookDetailInfo(bookUrl: String, loadEpisodes: Boolean, loadFullPages: Boolean): BookDetail {
        val data = getFiles(bookUrl, true)
        val list = mutableListOf<Episode>()
        run loop@{
            (0 until data.length()).forEach {
                val result = data.getJSONObject(it)
                val isDir = result.getInt("isdir")
                val path = result.getString("path")
                val category = result.getInt("category")

                val cName = path.substring(bookUrl.length + 1).replace("/", "-")
                if (isDir == 0) {
                    val fsid = result.getLong("fs_id").toString()
                    if (category == 2) {
                        list.add(Episode(cName, fsid))
                    } else if (category == 3) {
                        val coverStorage = getCoverStorage()
                        setCoverCache(coverStorage, bookUrl, fsid)
                        setCoverStorage(coverStorage)
                    }
                }
            }
        }

        return BookDetail(list.sortedBy { it.title })
    }

    fun getFiles(path: String, all: Boolean): JSONArray {
        var dataUrl =
            "https://pan.baidu.com/rest/2.0/xpan/file?method=list&access_token=${getToken()}&dir=${path}&order=name&limit=10000&web=web&showempty=0"
        if (all)
            dataUrl =
                "https://pan.baidu.com/rest/2.0/xpan/multimedia?method=listall&access_token=${getToken()}&path=${path}&recursion=1&limit=10000"
        return Fuel.get(dataUrl).responseJson().third.get().obj().getJSONArray("list")
    }

    fun getDLinks(fsids: Array<String>): Map<String, String> {
        val fsidStr = fsids.joinToString(",")
        val dataUrl =
            "https://pan.baidu.com/rest/2.0/xpan/multimedia?method=filemetas&access_token=${getToken()}&fsids=%5B${fsidStr}%5D&dlink=1"

        val response = Fuel.get(dataUrl).responseJson().third.get().obj()

        return response.getJSONArray("list").let { list ->
            (0 until list.length()).associate { index ->
                val item = list.getJSONObject(index)
                item.getLong("fs_id").toString() to item.getString("dlink") + "&access_token=${getToken()}"
            }
        }
    }
}